﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Av.Utils;
using System.Net;


namespace JrSnifTest
{
    public class IpHeader
    {

        /// <summary>
        /// Protocol type
        /// </summary>
        public byte Protocol = 0;

        public string ProtocolName
        {
            get
            {
                switch(Protocol)
                {
                    case 0x06:
                        return "TCP";
                    case 0x11:
                        return "UDP";
                }

                return string.Format("??{0}??", Protocol);
            }
        }

        public string DestinationIp { get; set; }

        public string SourceIp { get; set; }

        /// <summary>
        /// Contains data, w/o IP header
        /// </summary>
        public byte[] IpData { get; set; }

        public TcpHeader TcpHeader = null;

        public static IpHeader Parse(byte[] header)
        {
            return Parse(header, 0, header.Length);
        }

        public static IpHeader Parse(byte[] header, int offset, int len)
        {
            IpHeader h = new IpHeader();

            try
            {
                //Log4cs.Log("Parsing IP header from: {0}", Common.EncodeHex(header));
                MemoryStreamEx ms = new MemoryStreamEx(header, offset, len);
                byte b = 0;
                byte[] ba = null;

                b = (byte)ms.ReadByte();
                Log4cs.Log("Version of IP: {0}", ((b & 0x40) >> 4));

                // Length is specified in 32bits word
                int internetHeaderWords = b & 0xF;
                Log4cs.Log("Length of internet header: {0} (32 bits words)...", internetHeaderWords);

                // Differentiated Services Code Point and Explicit Congestion Notification
                ms.ReadByte();

                // Total length
                int length = 0;
                ba = ms.Read(2);
                Log4cs.Log("2 bytes of length: {0}", Common.EncodeHex(ba));
                length = ((ba[0] << 8) & 0xFF00) | ba[1];
                Log4cs.Log("Total length is: {0}", length);

                // Identification, Flags, Fragment Offset
                ba = ms.Read(4);

                // TTL
                b = (byte)ms.ReadByte();
                Log4cs.Log("TTL: {0}", b);

                // Protocol
                b = (byte)ms.ReadByte();
                h.Protocol = b;
                Log4cs.Log("Protocol is: 0x{0:X} ({1})", b, h.ProtocolName);

                // Header Checksum (2 bytes)
                ba = ms.Read(2);
                Log4cs.Log("IP header checksum: {0}", Common.EncodeHex(ba));

                // Source IP (4 bytes)
                ba = ms.Read(4);
                //Log4cs.Log("Source IP: {0}", Common.EncodeHex(ba, 0, 4));
                IPAddress ip = new IPAddress(ba);
                Log4cs.Log("Source IP: {0}", ip.ToString());
                h.SourceIp = ip.ToString();

                // Destination IP (4 bytes)
                ba = ms.Read(4);
                //Log4cs.Log("Destination IP: {0}", Common.EncodeHex(ba, 0, 4));
                ip = new IPAddress(ba);
                Log4cs.Log("Destination IP: {0}", ip.ToString());
                h.DestinationIp = ip.ToString();

                // Options and padding
                if( internetHeaderWords > 5 )
                {
                    //ms.Read(internetHeaderWords * 4);
                    ba = ms.Read(4);
                    Log4cs.Log("IP options (4 bytes): {0}", Common.EncodeHex(ba));
                }

                // Read all data to buffer
                h.IpData = ms.Read((int)(ms.Length - ms.Position));
                if( h.ProtocolName == "TCP" )
                {
                    h.TcpHeader = TcpHeader.Parse(h.IpData);
                }

                //Log4cs.Log(Importance.Debug, "64-96 bytes: {0}", Common.EncodeHex(ba, offset + 9, 1));
            } catch(Exception ex)
            {
                Log4cs.Log(Importance.Error, "Error parsing IP header!");
                Log4cs.Log(Importance.Debug, ex.ToString());
                
            }

            return h;
        }

        /// <summary>
        /// Returns IP protocol (integer) by first 4 bits of IP packet. TCP is 0x06, UDP is 0x11
        /// </summary>
        /// <param name="ba">IP packet</param>
        /// <param name="offset">Offset in byte array</param>
        public static int GetProtocol(byte[] ba, int offset)
        {
            //Log4cs.Log("IP protocol is: 0x{0:X}", ba[offset + 9]);
            return ba[offset + 9];
        }
    }
}
